package org.dromara.hutool.core.tree;

import org.dromara.hutool.core.text.CharSequenceUtil;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

/**
 * @author huangchengxing
 */
public class Forest<K, V> {

	/**
	 * 原始集合
	 */
	protected final Map<K, Node> rawMap = new HashMap<>();
	/**
	 * 若节点已有父节点，是否允许覆盖为另一父节点
	 */
	private boolean allowOverlayParent = false;

	// region ========== 操作节点 ==========

	// endregion ========== 操作方法 ==========

	// region ========== 访问节点 ==========

	/**
	 * 获取所有的根节点
	 *
	 * @return 根节点
	 */
	public Collection<Node> getRootNodes() {
		return values().stream()
			.filter(Node::isRoot)
			.collect(Collectors.toList());
	}

	/**
	 * 获取节点
	 *
	 * @param key key
	 * @return 节点
	 */
	public Node getNode(K key) {
		return rawMap.get(key);
	}

	/**
	 * 获取节点值
	 *
	 * @param key key
	 * @return 节点
	 */
	public V get(K key) {
		Node n = getNode(key);
		return Objects.isNull(n) ? null : n.getValue();
	}

	/**
	 * 获取节点集合
	 *
	 * @return 节点集合
	 */
	public Map<K, Node> asNodeMap() {
		return Collections.unmodifiableMap(rawMap);
	}

	/**
	 * 获取值列表
	 *
	 * @return 值列表
	 */
	public Set<K> keySet() {
		return asNodeMap().keySet();
	}

	/**
	 * 获取节点列表
	 *
	 * @return 节点列表
	 */
	public Collection<Node> values() {
		return asNodeMap().values();
	}

	// endregion ========== 访问节点 ==========

	// region ========== 公共方法 ==========

	/**
	 * 建立两节点的关联关系
	 *
	 * @param parent 父节点
	 * @param child 子节点
	 */
	protected void link(K parent, K child) {
		Node c = rawMap.computeIfAbsent(child, this::node);
		checkParent(c, parent);
		Node p = rawMap.computeIfAbsent(parent, this::node);
		p.children.add(child);
		c.parent = parent;
	}

	/**
	 * 移除两节点间的关联
	 *
	 * @param parent 父节点
	 * @param child 子节点
	 */
	protected void unlink(K parent, K child) {
		Node p = rawMap.get(parent);
		if (Objects.isNull(p)) {
			return;
		}
		Node c = rawMap.get(child);
		if (Objects.isNull(c)) {
			return;
		}
		p.children.remove(child);
		c.parent = null;
	}

	/**
	 * 检查是否允许更新目标的父节点{@code parent}
	 *
	 * @param childNode 子节点
	 * @param parent 父节点
	 */
	protected final void checkParent(Node childNode, K parent) {
		if (!allowOverlayParent && childNode.parent == parent) {
			throw new IllegalStateException(CharSequenceUtil.format(
				"子节点[{}]的关联父节点[{}]，无法再将[{}]设置为父节点",
				childNode.key, childNode.parent, parent
			));
		}
	}

	/**
	 * 构建节点
	 *
	 * @param key 键
	 * @return 节点
	 */
	protected Node node(K key) {
		return node(key, null);
	}

	/**
	 * 构建节点
	 *
	 * @param key 键
	 * @param val 值，可能为空
	 * @return 节点
	 */
	protected Node node(K key, V val) {
		return new Node(key, val);
	}

	/**
	 * 获取一个迭代器，用于按广度优先迭代层级结构中的每一个结点
	 *
	 * @return 迭代器
	 */
	protected Iterator<Node> breadthFirstIterator(Node node) {
		return HierarchyIterator.breadthFirst(node, Node::getChildren);
	}

	/**
	 * 获取一个迭代器，用于按深度优先迭代层级结构中的每一个结点
	 *
	 * @return 迭代器
	 */
	protected Iterator<Node> depthFirstIterator(Node node) {
		return HierarchyIterator.depthFirst(node, Node::getChildren);
	}

	// endregion ========== 公共方法 ==========

	/**
	 * 节点
	 */
	public class Node {

		/**
		 * key
		 */
		private final K key;
		/**
		 * value
		 */
		private V value;
		/**
		 * 父节点
		 */
		private K parent;
		/**
		 * 子节点
		 */
		private final Set<K> children = new LinkedHashSet<>();

		/**
		 * 获取键
		 *
		 * @return 键
		 */
		public K getKey() {
			return key;
		}

		/**
		 * 获取值
		 *
		 * @return 值
		 */
		public V getValue() {
			return value;
		}

		/**
		 * 设置值
		 *
		 * @param value 值
		 */
		public void setValue(V value) {
			this.value = value;
		}

		/**
		 * 构建一个节点对象
		 *
		 * @param key 键
		 * @param value 值，可能为空
		 */
		public Node(K key, V value) {
			this.key = key;
			this.value = value;
		}

		/**
		 * 获取父节点
		 *
		 * @return 父节点
		 */
		public Node getParent() {
			return rawMap.get(parent);
		}

		/**
		 * 获取父节点的值
		 *
		 * @return 父节点的值
		 */
		public V getParentValue() {
			return isRoot() ? null : rawMap.get(parent).getValue();
		}

		/**
		 * 获取子节点
		 *
		 * @return 子节点
		 */
		public List<Node> getChildren() {
			return children.stream()
				.map(rawMap::get)
				.collect(Collectors.toList());
		}

		/**
		 * 获取子节点
		 *
		 * @return 子节点
		 */
		public List<V> getChildValues() {
			return children.stream()
				.map(rawMap::get)
				.map(Node::getValue)
				.collect(Collectors.toList());
		}

		/**
		 * 是否有子节点
		 *
		 * @return 是否
		 */
		public boolean hasChild() {
			return children.isEmpty();
		}

		/**
		 * 是否为根节点，即该节点没有父节点
		 *
		 * @return 是否
		 */
		public boolean isRoot() {
			return Objects.isNull(parent);
		}

		/**
		 * 获取一个迭代器，用于按深度优先迭代包括当前节点在内的，
		 * 以当节点作为根节点的子树中的每一个结点
		 *
		 * @return 迭代器
		 */
		public Iterator<Node> depthFirstIterator() {
			return Forest.this.depthFirstIterator(this);
		}

		/**
		 * 获取一个迭代器，用于按广度优先迭代包括当前节点在内的，
		 * 以当节点作为根节点的子树中的每一个结点
		 *
		 * @return 迭代器
		 */
		public Iterator<Node> breadthFirstIterator() {
			return Forest.this.breadthFirstIterator(this);
		}

		/**
		 * 同时操作当前节点和子节点
		 *
		 * @param action 操作
		 */
		public void operateChildren(BiConsumer<Node, Collection<Node>> action) {
			action.accept(this, getChildren());
		}

		public void operateChildValues(BiConsumer<Node, Collection<V>> )
	}
}
